home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 15 / BBS in a box XV-2.iso / Files II / Newton / Resources / Creative Digital Systems / CreativeDig.sit / RTFMDesc.txt < prev    next >
Encoding:
Text File  |  1994-11-22  |  17.0 KB  |  331 lines  |  [TEXT/R*ch]

  1. NewtRTFM: Case Study of a Runaway Newton Application
  2. Sandeep Shah
  3. K2 Consultants, Inc.
  4. sandeep@zk3.dec.com
  5.  
  6. THIS ARTICLE WAS FIRST PUBLISHED IN PDA DEVELOPERS (FORMERLY PIE DEVELOPERS)
  7. MAGAZINE. COPYRIGHT (C) 1994 BY CREATIVE DIGITAL SYSTEMS. ALL RIGHTS RESERVED.
  8. CONTACT CREATIVE DIGITAL SYSTEMS AT CDS@NETCOM.COM FOR MORE INFORMATION. 
  9.  
  10. NewtRTFM is a Newton-resident portable reference for the Newton developers.
  11. You may ask: why do I care? (Translation: why isn't it in the ad pages that I
  12. can conveniently skip?) A fair question. A discussion about why I decided to
  13. develop it and how I went about doing it can induce important lessons about
  14. the stages of the design and implementation of a large PDA application.
  15. Hopefully, my replay of the (loud) thinking process will help you see a few
  16. parallels in the nutty problems you are trying to crack yourself.
  17.  
  18. HOW IT ALL STARTED 
  19. Since August 1993, Newton pioneers have had an interesting love-hate
  20. relationship with Newton Programming. I am talking about the Newton Toolkit
  21. (NTK). It was clear that the Newton had potential, and it was also clear that
  22. the development environment would have to mature, especially the alpha
  23. documentation that accompanied the beta software.
  24.     The following problems hindered the learning process in the first few
  25. months:
  26.  
  27. * missing or misleading information about functions, protos, classes,
  28. behavior and other NewtonScript constructs;
  29. * inconsistencies in function names;
  30. * confusion about choosing methods instead of global functions;
  31. * some not-so-obvious bugs in the early incarnations of the ROMs and
  32. Platform files;
  33. * no effective mechanism to print and study program listings.
  34.  
  35. In spite of the furious efforts by PIE DTS to answer questions through Q&As
  36. and the net, the basic task of pulling it all together remained a daunting
  37. one.
  38.     This is where NewtRTFM enters. I wanted to have a single source
  39. documentation that would be as portable as the Newton itself. That way I
  40. could convert a little bit of spare time at the oddest of places into a
  41. productive time to work on my favorite Newton project.
  42.     Every developer knows how precious desktop screen real estate is when you
  43. are in the middle of development. An electronic reference on the host would
  44. be a bit inconvenient, disorienting and intrusive. Putting the reference on
  45. the Newton, however, seemed like a good solution - when you are busy using
  46. the Mac keyboard and wondering about the most appropriate function to use,
  47. your Newton is just sitting there. Even when you're not near your development
  48. environment, a Newton-based reference can still be useful.
  49.  
  50. BASIC DESIGN DECISIONS
  51. Being from the Unix world, I have a strong attachment to the man pages that
  52. provide on-line documentation about commands, system calls, arguments, return
  53. values and other essential topics. I decided that this approach, coupled with
  54. the combining of related topics into various categories, could make the whole
  55. application tremendously useful for developers from beginning to expert
  56. level. 
  57.     The next important decision was deciding what information to include. In
  58. order to be useful to a programmer NewtRTFM had to include all functions,
  59. methods, protos, view classes, behavior slots and so on. This had a direct
  60. bearing on the navigational structure. While it's easier to enter a name on a
  61. keyboard-based machine, typing a name on a Newton is hardly an effective way
  62. to look up a topic. (Letting a user say "show SendRemoteControlCode" through
  63. the note pad can be a cute demo, a la "fax Bob," but it's not really
  64. convenient). Besides, we need to consider the cases where a topic name is
  65. known, partially known or totally unknown.
  66.     Taking a cue from indices (as opposed to tables of content), I decided it
  67. was easiest to split the name space by the first letter of each topic name.
  68. Another way to organize that information would be to filter it by various
  69. categories, such as "System Messages." The important lesson here is to
  70. provide fast paths without relying too much on the information that needs to
  71. be written or typed in.
  72.     Next problem was the content within these topics. I decided that the
  73. content should be minimal - a lot of verbiage would mean a lot of storage
  74. which would render the project practically impossible. Also, it would make it
  75. much harder to locate needed information quickly. (A serious modern-day
  76. problem is not one of no information, but of too much information).
  77.      I decided to compartmentalize the information for every topic so you
  78. could quickly zero in on the needed information. For example, you might know
  79. that the Array() function creates an array, but you need to know the type and
  80. the order of each argument. On the other hand you may need to brush up on
  81. FindStringInFrame() by reading a brief description. The other two useful
  82. items I decided to include were a sensible example and personal annotation. 
  83.  
  84. An Application, not a Book
  85. Let me take a quick detour to list my reasons for not doing a Newton
  86. book.    
  87.     At  first glance, this may seem like an ideal situation to create a
  88. Newton Book. However, after having worked with various hypertext-based
  89. programming references as a user, I decided against it for a few reasons:
  90.  
  91. * Linked topics and navigation have a disorienting effect on the reader
  92. because of the lack of a relative context and locality. 
  93. * When the task is for reference, you are interested in zeroing on the
  94. needed information quickly.
  95. * The size of the book would be very large. As you see later, some of the
  96. tricks I used to save space may not lend themselves well to the Bookmaker
  97. format.
  98.  
  99. PUTTING IT ALL TOGETHER
  100. Enough rambling about the preparation. Let's delve into the interface I came
  101. up with (see Figure 1). Note that after going through multiple iterative
  102. experiments, I decided that the most effective interface was to have a
  103. wallpaper-style interface (much like the built-in paper Roll), allowing
  104. enough hooks to let you do your routine tasks.
  105.     With this interface, the main portion of the screen shows the details for
  106. a particular topic. There are four tabs on the right-hand side of the main
  107. view - info, args, show and note - for viewing a description, an argument
  108. summary, an example and your personal notations. There are also four primary
  109. navigation aids:
  110.  
  111. * the alphabetic palette at the bottom lets you selecting a topic
  112. alphabetically;
  113. * the All button lets you select a subset of topics by category;
  114. * the GoTo button lets you look up a topic by partial string match; and
  115. * the arrows at the top of the screen let you sequence through the current
  116. set of topics.
  117.  
  118. These navigation aids satisfied my need to find any topic or detail quickly.
  119.     I first implemented a small floating alphabet that showed "A" through "Z"
  120. like the Name application. If you tapped on a letter it displayed a popup of
  121. all the topics starting with that letter. Selecting an item switched to that
  122. topic. This approach had two problems:
  123.  
  124. * A child view can't be bigger than its parent view - I had to change the
  125. alphabet's viewBounds with SetValue() just before showing this view. This was
  126. slow and distracting.
  127. * I realized that any reference session consists of looking up multiple
  128. topics - the topic information stays on the screen all the time. The alphabet
  129. palette end up being an annoying distraction. 
  130.  
  131. MAJOR CHALLENGES
  132. Now lets look at the serious challenges and what I tried to counter them. 
  133.  
  134. Soup or Not?
  135. NewtRTFM's data is primarily read-only. Looking at soup overhead and
  136. performance, I decided to put the data within the package itself. I
  137. experimented with some homegrown indexing that is easy to implement in
  138. NewtonScript because of the flexibility of frames and arrays. (Most of my
  139. experiments are similar in spirit, although not as elegantly executed, to
  140. those outlined in "Lost In Space" by Mike Engber in PIE Developers 2.3). I
  141. chose a hybrid method using a "frame-of-array-of-frames" with "meta-indexing"
  142. that is hard coded to my needs.
  143.  
  144. A Special Popup
  145. One of the important navigational features is the alphabetic palette that
  146. lets you see a popup of all topics that begin with the letter you tap. A
  147. popup is simple to do with the DoPopup() function. However, it does not
  148. handle the case where the items span multiple screens. I had to create a
  149. multi-screen popup of my own (see Figure 2). 
  150.     I used a view based on clPickView with a method :DoPopup that takes the
  151. same arguments as DoPopup() and add the meta items [--Next--] and [--Prev--] in
  152. the subset of the large list. With a little logic in the pickActionScript to
  153. detect if one of these meta items is tapped. 
  154.     (Due to many requests, I am in the process of finalizing this popup as a
  155. public domain user proto that can be used by anyone who is interested).
  156.  
  157. Runtime vs. Compile-time Trade-offs
  158. After a brief flirtation with building the indexing structures in the
  159. InstallScript, I stumbled upon the wonderful AfterScript. This is where most
  160. of my raw data massaging occurs. Whatever you do in an InstallScript has
  161. runtime implications (both time spent while installing and resetting the
  162. Newton, as well as the RAM used). It's better to do those things that are
  163. known at build time using an AfterScript. Note that most of the data
  164. management and utility functions and the NewtonScript language constructs are
  165. available in the NTK environment and can be leveraged in an AfterScript.
  166. Also, it's possible to provide cross references to objects that reside on
  167. your built package. (The next section of this article shows another possible
  168. use of AfterScripts). 
  169.     As an example, if you have some data under development, and you want to
  170. select only certain data on the basis of some compile-time constant, you can
  171. use an AfterScript in the template that contains the selection information. I
  172. use this technique to compile the project for a demo version of NewtRTFM (as
  173. well as for a quick compile) by filtering out most of the data while building
  174. the project.    
  175.     
  176. // The following file contains data in a large 
  177. // frame with one slot for each letter of the 
  178. // alphabet. For each alphabet, there is an array 
  179. // of frames, one frame for each entry
  180. //
  181. // Load command will have this large frame in 
  182. // allData
  183. //
  184. Load (HOME & "allData.f");
  185.  
  186. //
  187. // This is the AfterScript for the base view
  188. // Note that this is not a func, just a compound
  189. // statement
  190. //
  191. AfterScript: 
  192.     begin
  193.         // Iterate over all "letters" to filter data
  194.      foreach alphaSym in 
  195.         ['a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'k,
  196.         'l, 'm, 'n, 'o, 'p, 'q, 'r, 's, 't, 'u,
  197.         'v, 'w] do
  198.      begin
  199.         if (allData.(alphaSym)) then 
  200.         begin
  201.             // "print" is useful for printing the 
  202.             // compile time stuff to the inspector! 
  203.             print("Slot" && alphaSym && "present")    
  204.              abc := []; // none to start with
  205.              foreach item in allDope.(alphaSym) do
  206.              begin     
  207.                  // now decide if we want this or not
  208.                 // 'kHasStuff is another script in the
  209.                 // Project Data that returns TRUE if 
  210.                 // this item is to be included, NIL 
  211.                 // otherwise
  212.                  if (Call kHasStuff with (alphaSym, item)) then
  213.                  begin
  214.                      AddArraySlot(abc, item);
  215.                  end;         
  216.              end; // foreach item
  217.              // replace the slot
  218.              allDope.(alphaSym) := abc;
  219.         end;    // if (allData.(alphaSym))
  220.     end;    // foreach all symbols
  221. end;    // End of AfterScript
  222.  
  223. Size
  224. As I started stuffing NewtRTFM with its contents, the package started to
  225. bloat, thanks to Unicode's two-byte characters. This is where the duo
  226. StuffCString() and ExtractCString() came to my help. Since there is no
  227. support for doing this directly through NTK (unless I surround all my string
  228. with StuffCString), I resort to compressing the data using StuffCString in
  229. the same AfterScript mentioned earlier. This almost halves the size of the
  230. program, saving me almost 600K bytes in the final package. 
  231.     Since C strings are reasonable candidates for compression, the final
  232. package gets compressed to nearly half the size of the uncompressed data. In
  233. my experiments, by keeping the package uncompressed, the speed improvement
  234. came to just about 10%, hardly noticeable during the interaction. Keeping it
  235. compressed clearly has much more merit.
  236.  
  237. Live Examples
  238. Apple provides many samples illustrating various NewtonScript features. I
  239. found it hard to try and refer to something effectively while developing an
  240. application. For example I may want to check out some sample which includes
  241. clParagraphView. Usually it's cumbersome in the middle of development to go
  242. find the correct sample and extract the right feature from it. I wanted to
  243. provide some sort of link to useful samples. 
  244.     Since it is not practical to keep hundreds of full-fledged samples on a
  245. Newton, I required an alternative. Once again keeping with the theme of
  246. supplying just the needed information, I included an example that would
  247. illustrate the exact usage for a topic. Most of the topics that have a visual
  248. or sound effect are also live, meaning they execute automatically when you go
  249. to the show page. 
  250.     For example if you are looking at building a view using
  251. protoExpandoShell, wouldn't it be nice to see a sample that shows how to
  252. create one? That's exactly what I wanted NewtRTFM to do. Go to the topic,
  253. open the show page and you see an example, complete with protoTextExpando,
  254. protoPhoneExpando and protoPhoneExpando children (see Figure 3). If you want
  255. to see behind the curtains, just close the view and you find the NewtonScript
  256. source code that shows you how it was done (see Figure 4). If you want to use
  257. the text, there is a simple way to cut and paste it to the Inspector or to
  258. ViewFrame. 
  259.  
  260. OTHER TASKS
  261. Let's look at some of the other things you may need to do while developing an
  262. application:
  263.  
  264. * open the standard Newton programs such as Names, Dates;
  265. * open and close the Newton Toolkit slip,
  266. * open other applications that are in the Extras drawer;
  267. * open the application you're working on; or
  268. * write notes.
  269.  
  270. The first task is easily handled, thanks to the Newton's fixed button bar. I
  271. decided to include some shortcuts to make it easy to accomplish some of these
  272. other tasks:
  273.     The three "holes" on the left side of NewtRTFM's page are ideal
  274. candidates for buttons that I can attach a function to:
  275.  
  276. * The top button launches the Toolkit. It's marked with "i" for Inspector.
  277. * The bottom button ("a" for Applications) displays an alphabetical popup
  278. list of all the programs in the Extras drawer. You can start any of those
  279. applications from the popup.
  280. * The remaining button ("e" for Extras and Express) provides an
  281. interesting feature. Until you use the Extras button to launch an
  282. application, this button brings up the Extras drawer. After you open an
  283. application using the Applications button, this button acts as an Express
  284. launcher for that program. Usually this is the program under development. 
  285.  
  286. INTERESTING BUGS
  287. Well, are bugs ever really interesting? (Yes, but only in retrospect).
  288. NewtonScript is deceptively simple. But bugs in large applications are hardly
  289. that. Here is a quick list of what I faced and the reasons.
  290.  
  291. ClEditView
  292. This one drove me nuts. Normally you wouldn't have a viewClickScript defined
  293. for your view based on this class, because the default action is good enough.
  294. But watch out if you have viewClickScripts in the parent hierarchy. If any of
  295. them return TRUE, no matter how "distant" the grand parent is, the default
  296. action for the clEditView is dropped. The end result is no ink or data in the
  297. view. Although now it seems trivial and obvious, it wasn't, until I tried
  298. everything else under the sun.
  299.  
  300. Sort()
  301. I encountered another bug as a result of ignoring an important side effect of
  302. the Sort() function. I used a simple-looking sort on the extras array in the
  303. global heap:
  304.     
  305.     local apps := sort(extras, '|<str|, 'text);
  306.  
  307. so that I could iterate over each item to collect names to be displayed in a
  308. popup. Can you see the problem here right away? If you don't, write "Sort is
  309. destructive to the source array" 1000 times. The interesting thing was that
  310. it wouldn't cause any problems until I tried to delete an application. Then
  311. my Newton would freeze and the program would vanish, but it's memory would
  312. never be released.
  313.  
  314. My Newton has Amnesia
  315. I had a central script that I would call for every display event in a topic.
  316. I found that every time I used it, there would be a leakage of frames heap
  317. memory by up to 1K. I wrote a second application that used the data from
  318. NewtRTFM and displayed it in a similar view hierarchy in a round-robin
  319. fashion. No losses. I rewrote the script by splitting it into multiple pieces
  320. (same code) and the leakage went away. The only reason I can suggest for the
  321. leak was a large number of locals (around 21) that I was using in the
  322. original script. There's no definite conclusion I can draw here, but I
  323. learned to keep things small and simple.
  324.  
  325. CONCLUSION
  326. This turned out to be a very interesting project, enriching my knowledge
  327. about Newton development from all possible angles. Trying to come up with
  328. samples that make sense and work interactively proved to be a challenging
  329. task. No matter what, the Newton is a fun platform to work with and I hope
  330. that NewtRTFM helps convey that image.
  331.